package com.xunwulian.weixin.h5.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.google.gson.Gson;
import com.xunwulian.api.iface.SubscriberAPI;
import com.xunwulian.api.iface.UserAPI;
import com.xunwulian.base.constant.ConstantBean;
import com.xunwulian.base.entity.SubscriberEntity;
import com.xunwulian.base.entity.User;
import com.xunwulian.weixin.h5.service.CoreService;
import com.xunwulian.weixin.h5.util.ReturnModel;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpConfigStorage;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@Controller
public class CoreController extends GenericController {

    @Autowired
    protected WxMpConfigStorage configStorage;

    @Autowired
    protected WxMpService wxMpService;

    @Autowired
    protected CoreService coreService;

    @Reference
    private UserAPI userAPI;
    @Reference
    private SubscriberAPI subscriberAPI;

    @RequestMapping(value = "index")
    public String index() {
        return "index";
    }

    /**
     * 微信公众号webservice主服务接口，提供与微信服务器的信息交互
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "core")
    public void wechatCore(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setContentType("text/html;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);

        String signature = request.getParameter("signature");
        String nonce = request.getParameter("nonce");
        String timestamp = request.getParameter("timestamp");

        if (!this.wxMpService.checkSignature(timestamp, nonce, signature)) {
            // 消息签名不正确，说明不是公众平台发过来的消息
            response.getWriter().println("非法请求");
            return;
        }

        String echoStr = request.getParameter("echostr");
        if (StringUtils.isNotBlank(echoStr)) {
            // 说明是一个仅仅用来验证的请求，回显echostr
            String echoStrOut = String.copyValueOf(echoStr.toCharArray());
            response.getWriter().println(echoStrOut);
            return;
        }

        String encryptType = StringUtils.isBlank(request.getParameter("encrypt_type"))
                ? "raw"
                : request.getParameter("encrypt_type");

        if ("raw".equals(encryptType)) {
            // 明文传输的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(request.getInputStream());
            WxMpXmlOutMessage outMessage = this.coreService.route(inMessage);
            response.getWriter().write(outMessage.toXml());
            return;
        }

        if ("aes".equals(encryptType)) {
            // 是aes加密的消息
            String msgSignature = request.getParameter("msg_signature");
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(
                    request.getInputStream(), this.configStorage, timestamp, nonce,
                    msgSignature);
            this.logger.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
            WxMpXmlOutMessage outMessage = this.coreService.route(inMessage);
            this.logger.info(response.toString());
            response.getWriter()
                    .write(outMessage.toEncryptedXml(this.configStorage));
            return;
        }

        response.getWriter().println("不可识别的加密类型");
        return;
    }

    /**
     * 通过openid获得基本用户信息
     * 详情请见: http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html
     *
     * @param response
     * @param openid   openid
     * @param lang     zh_CN, zh_TW, en
     */
    @RequestMapping(value = "getUserInfo")
    public WxMpUser getUserInfo(HttpServletResponse response,
                                @RequestParam(value = "openid") String openid,
                                @RequestParam(value = "lang") String lang) {
        ReturnModel returnModel = new ReturnModel();
        WxMpUser wxMpUser = null;
        try {
            wxMpUser = this.wxMpService.getUserService().userInfo(openid, lang);
            returnModel.setResult(true);
            returnModel.setDatum(wxMpUser);
            renderString(response, returnModel);
        } catch (WxErrorException e) {
            returnModel.setResult(false);
            returnModel.setReason(e.getError().toString());
            renderString(response, returnModel);
            this.logger.error(e.getError().toString());
        }
        return wxMpUser;
    }

    /**
     * 2.获得access token
     * 当用户同意授权后，会回调所设置的url并把authorization code传过来
     */
    @RequestMapping(value = "getOAuth2UserInfo")
    public void getOAuth2UserInfo(HttpServletResponse response,
                                  @RequestParam(value = "code") String code,
                                  @RequestParam(value = "state") String state) {
        ReturnModel returnModel = new ReturnModel();
        WxMpOAuth2AccessToken accessToken;
        WxMpUser wxMpUser;

        String lang = "zh_CN";

        try {
            // 2.1然后用这个code获得access token，其中也包含用户的openid等信息
            accessToken = this.wxMpService.oauth2getAccessToken(code);
            // 2.2 获得用户基本信息
            wxMpUser = this.wxMpService.getUserService().userInfo(accessToken.getOpenId(), lang);

            returnModel.setResult(true);
            returnModel.setDatum(wxMpUser);
//            renderString(response, returnModel);

            Gson gson = new Gson();
            logger.info("userId:" + gson.toJson(wxMpUser));

            ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
            HttpSession session = attr.getRequest().getSession();
            session.setAttribute(wxMpUser.getOpenId(), wxMpUser);

            String userId = ConstantBean.TEST_USER_ID;
            String userName = ConstantBean.TEST_USER_NAME;
            String openId = ConstantBean.TEST_OPEN_ID;

            SubscriberEntity subscriberEntity = subscriberAPI.findByOpenId(wxMpUser.getOpenId()).getData();

            logger.info("subscriberEntity, " + gson.toJson(subscriberEntity));

            // 是否订阅过
            if (subscriberEntity != null) {

                openId = subscriberEntity.getOpenId();

                if (subscriberEntity.getUserId() != null && !"".equals(subscriberEntity.getUserId())) {
                    userId = subscriberEntity.getUserId();

                    User user = userAPI.getByUid(userId);
                    userName = user.getUSERNAME();

                    logger.info("user:" + gson.toJson(user));
                }

                logger.info("subscriberEntity exists, openId:" + openId + ", uid:" + userId);
            } else {

                subscriberEntity = new SubscriberEntity(wxMpUser.getSubscribe(),
                        wxMpUser.getOpenId(),
                        "",
                        wxMpUser.getNickname(),
                        wxMpUser.getSex(),
                        wxMpUser.getLanguage(),
                        wxMpUser.getCity(),
                        wxMpUser.getProvince(),
                        wxMpUser.getCountry(),
                        wxMpUser.getHeadImgUrl(),
                        wxMpUser.getUnionId(),
                        wxMpUser.getRemark());

                subscriberAPI.add(subscriberEntity);

                // 新用户UserId使用默认值
                openId = wxMpUser.getOpenId();
                System.out.print("add subscriberEntity, openId:" + openId + ", uid:" + userId);
            }

            response.addCookie(new Cookie("userId", userId));
            response.addCookie(new Cookie("userName", userName));
            response.addCookie(new Cookie("openId", openId));
            response.addCookie(new Cookie("testCookie", "testCookie"));

            System.out.print("openId:" + openId + ", uid:" + userId);

            response.sendRedirect("index.html");

        } catch (WxErrorException e) {
            returnModel.setResult(false);
            returnModel.setReason(e.getError().toString());
            renderString(response, returnModel);
            this.logger.error(e.getError().toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 用code换取oauth2的openid
     * 详情请见: http://mp.weixin.qq.com/wiki/1/8a5ce6257f1d3b2afb20f83e72b72ce9.html
     *
     * @param response
     * @param code     code
     */
    @RequestMapping(value = "getOpenid")
    public void getOpenid(HttpServletResponse response, @RequestParam(value = "code") String code) {
        ReturnModel returnModel = new ReturnModel();
        WxMpOAuth2AccessToken accessToken;
        try {
            accessToken = this.wxMpService.oauth2getAccessToken(code);
            returnModel.setResult(true);
            returnModel.setDatum(accessToken.getOpenId());
            renderString(response, returnModel);
        } catch (WxErrorException e) {
            returnModel.setResult(false);
            returnModel.setReason(e.getError().toString());
            renderString(response, returnModel);
            this.logger.error(e.getError().toString());
        }
    }

}
